package org.greatlogic.gxtexamples.client.glgwt;
/*
 * Copyright 2006-2014 Andy King (GreatLogic.com)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.TreeMap;
import org.greatlogic.gxtexamples.client.glgwt.GLValueProviderClasses.GLBigDecimalValueProvider;
import org.greatlogic.gxtexamples.client.glgwt.GLValueProviderClasses.GLBooleanValueProvider;
import org.greatlogic.gxtexamples.client.glgwt.GLValueProviderClasses.GLDateValueProvider;
import org.greatlogic.gxtexamples.client.glgwt.GLValueProviderClasses.GLForeignKeyValueProvider;
import org.greatlogic.gxtexamples.client.glgwt.GLValueProviderClasses.GLIntegerValueProvider;
import org.greatlogic.gxtexamples.client.glgwt.GLValueProviderClasses.GLStringValueProvider;
import org.greatlogic.gxtexamples.client.glgwt.IGLEnums.EGLColumnDataType;
import com.google.gwt.cell.client.DateCell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.safecss.shared.SafeStyles;
import com.google.gwt.safecss.shared.SafeStylesUtils;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.cell.core.client.NumberCell;
import com.sencha.gxt.cell.core.client.form.CheckBoxCell;
import com.sencha.gxt.core.client.IdentityValueProvider;
import com.sencha.gxt.core.client.ValueProvider;
import com.sencha.gxt.core.client.util.TextMetrics;
import com.sencha.gxt.data.shared.Converter;
import com.sencha.gxt.data.shared.LabelProvider;
import com.sencha.gxt.data.shared.Store;
import com.sencha.gxt.widget.core.client.ContentPanel;
import com.sencha.gxt.widget.core.client.Dialog.PredefinedButton;
import com.sencha.gxt.widget.core.client.box.AlertMessageBox;
import com.sencha.gxt.widget.core.client.box.ConfirmMessageBox;
import com.sencha.gxt.widget.core.client.box.ProgressMessageBox;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.container.BoxLayoutContainer.BoxLayoutPack;
import com.sencha.gxt.widget.core.client.event.ColumnWidthChangeEvent;
import com.sencha.gxt.widget.core.client.event.ColumnWidthChangeEvent.ColumnWidthChangeHandler;
import com.sencha.gxt.widget.core.client.event.DialogHideEvent;
import com.sencha.gxt.widget.core.client.event.DialogHideEvent.DialogHideHandler;
import com.sencha.gxt.widget.core.client.event.HeaderContextMenuEvent;
import com.sencha.gxt.widget.core.client.event.HeaderContextMenuEvent.HeaderContextMenuHandler;
import com.sencha.gxt.widget.core.client.event.RefreshEvent;
import com.sencha.gxt.widget.core.client.event.RowClickEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent.SelectHandler;
import com.sencha.gxt.widget.core.client.form.BigDecimalField;
import com.sencha.gxt.widget.core.client.form.ComboBox;
import com.sencha.gxt.widget.core.client.form.DateField;
import com.sencha.gxt.widget.core.client.form.DateTimePropertyEditor;
import com.sencha.gxt.widget.core.client.form.IntegerField;
import com.sencha.gxt.widget.core.client.form.IsField;
import com.sencha.gxt.widget.core.client.form.TextField;
import com.sencha.gxt.widget.core.client.grid.CheckBoxSelectionModel;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;
import com.sencha.gxt.widget.core.client.grid.Grid;
import com.sencha.gxt.widget.core.client.grid.GridSelectionModel;
import com.sencha.gxt.widget.core.client.grid.GridView;
import com.sencha.gxt.widget.core.client.grid.editing.GridEditing;
import com.sencha.gxt.widget.core.client.grid.editing.GridInlineEditing;
import com.sencha.gxt.widget.core.client.menu.Item;
import com.sencha.gxt.widget.core.client.menu.MenuItem;

public abstract class GLGridWidget implements IsWidget {
//--------------------------------------------------------------------------------------------------
private final HashSet<ColumnConfig<GLRecord, ?>> _checkBoxSet;
private ContentPanel                             _contentPanel;
private Grid<GLRecord>                           _grid;
protected ArrayList<GLGridColumnDef>             _gridColumnDefList;
private TreeMap<String, GLGridColumnDef>         _gridColumnDefMap;
protected GLListStore                            _listStore;
private final String                             _noRowsMessage;
private GridSelectionModel<GLRecord>             _selectionModel;
//--------------------------------------------------------------------------------------------------
protected GLGridWidget(final String headingText, final String noRowsMessage) {
  super();
  _noRowsMessage = noRowsMessage == null ? "There are no results to display" : noRowsMessage;
  _listStore = new GLListStore();
  _checkBoxSet = new HashSet<ColumnConfig<GLRecord, ?>>();
  _gridColumnDefList = new ArrayList<GLGridColumnDef>();
  loadGridColumnDefList();
  createGridColumnDefMap();
  createContentPanel(headingText);
  createGrid();
  _contentPanel.add(_grid);
}
//--------------------------------------------------------------------------------------------------
private void addHeaderContextMenuHandler() {
  final HeaderContextMenuHandler headerContextMenuHandler = new HeaderContextMenuHandler() {
    @Override
    public void onHeaderContextMenu(final HeaderContextMenuEvent headerContextMenuEvent) {
      MenuItem menuItem = new MenuItem("Size To Fit");
      menuItem.addSelectionHandler(new SelectionHandler<Item>() {
        @Override
        public void onSelection(final SelectionEvent<Item> selectionEvent) {
          resizeColumnToFit(headerContextMenuEvent.getColumnIndex());
          _grid.getView().refresh(true);
        }
      });
      headerContextMenuEvent.getMenu().add(menuItem);
      menuItem = new MenuItem("Size All To Fit");
      menuItem.addSelectionHandler(new SelectionHandler<Item>() {
        @Override
        public void onSelection(final SelectionEvent<Item> selectionEvent) {
          final ProgressMessageBox messageBox = new ProgressMessageBox("Size All Columns", //
                                                                       "Resizing Columns...");
          messageBox.setProgressText("Calculating...");
          //          messageBox.setPredefinedButtons();
          messageBox.show();
          resizeNextColumn(messageBox, _selectionModel instanceof CheckBoxSelectionModel ? 1 : 0,
                           _grid.getColumnModel().getColumnCount() - 1);
        }
      });
      headerContextMenuEvent.getMenu().add(menuItem);
    }
  };
  _grid.addHeaderContextMenuHandler(headerContextMenuHandler);
}
//--------------------------------------------------------------------------------------------------
@Override
public Widget asWidget() {
  return _contentPanel;
}
//--------------------------------------------------------------------------------------------------
private void centerCheckBox(final ColumnConfig<GLRecord, ?> columnConfig) {
  final int leftPadding = (columnConfig.getWidth() - 12) / 2;
  final String styles = "padding: 3px 0px 0px " + leftPadding + "px;";
  final SafeStyles textStyles = SafeStylesUtils.fromTrustedString(styles);
  columnConfig.setColumnTextStyle(textStyles);
}
//--------------------------------------------------------------------------------------------------
private void createCheckBoxSelectionModel() {
  final IdentityValueProvider<GLRecord> identityValueProvider;
  identityValueProvider = new IdentityValueProvider<GLRecord>();
  _selectionModel = new CheckBoxSelectionModel<GLRecord>(identityValueProvider) {
    @Override
    protected void onRefresh(final RefreshEvent event) {
      if (isSelectAllChecked()) {
        selectAll();
      }
      super.onRefresh(event);
    }
  };
}
//--------------------------------------------------------------------------------------------------
private ColumnConfig<GLRecord, BigDecimal> createColumnConfigBigDecimal(final GLGridColumnDef gridColumnDef,
                                                                        final IGLColumn column) {
  final ColumnConfig<GLRecord, BigDecimal> result;
  final ValueProvider<GLRecord, BigDecimal> valueProvider;
  valueProvider = new GLBigDecimalValueProvider(column, column.getNumberOfDecimalPlaces());
  result = new ColumnConfig<GLRecord, BigDecimal>(valueProvider, gridColumnDef.getWidth(), //
                                                  column.getTitle());
  result.setHorizontalAlignment(gridColumnDef.getHorizontalAlignment());
  NumberFormat numberFormat;
  if (column.getDataType() == EGLColumnDataType.Currency) {
    numberFormat = NumberFormat.getSimpleCurrencyFormat();
  }
  else {
    numberFormat = NumberFormat.getDecimalFormat();
  }
  result.setCell(new NumberCell<BigDecimal>(numberFormat));
  return result;
}
//--------------------------------------------------------------------------------------------------
private ColumnConfig<GLRecord, Boolean> createColumnConfigBoolean(final GLGridColumnDef gridColumnDef,
                                                                  final IGLColumn column) {
  final ColumnConfig<GLRecord, Boolean> result;
  final ValueProvider<GLRecord, Boolean> valueProvider = new GLBooleanValueProvider(column);
  result = new ColumnConfig<GLRecord, Boolean>(valueProvider, gridColumnDef.getWidth(), //
                                               column.getTitle());
  result.setHorizontalAlignment(gridColumnDef.getHorizontalAlignment());
  result.setCell(new CheckBoxCell());
  result.setSortable(false);
  _checkBoxSet.add(result);
  return result;
}
//--------------------------------------------------------------------------------------------------
private ColumnConfig<GLRecord, Date> createColumnConfigDateTime(final GLGridColumnDef gridColumnDef,
                                                                final IGLColumn column,
                                                                final String dateTimeFormat) {
  final ColumnConfig<GLRecord, Date> result;
  final ValueProvider<GLRecord, Date> valueProvider = new GLDateValueProvider(column);
  result = new ColumnConfig<GLRecord, Date>(valueProvider, gridColumnDef.getWidth(), //
                                            column.getTitle());
  result.setHorizontalAlignment(gridColumnDef.getHorizontalAlignment());
  final DateCell dateCell = new DateCell(DateTimeFormat.getFormat(dateTimeFormat));
  result.setCell(dateCell);
  return result;
}
//--------------------------------------------------------------------------------------------------
private ColumnConfig<GLRecord, String> createColumnConfigForeignKey(final GLGridColumnDef gridColumnDef,
                                                                    final IGLColumn column) {
  final ColumnConfig<GLRecord, String> result;
  final ValueProvider<GLRecord, String> valueProvider = new GLForeignKeyValueProvider(column);
  result = new ColumnConfig<GLRecord, String>(valueProvider, gridColumnDef.getWidth(), //
                                              column.getTitle());
  result.setHorizontalAlignment(gridColumnDef.getHorizontalAlignment());
  result.setCell(new TextCell());
  return result;
}
//--------------------------------------------------------------------------------------------------
private ColumnConfig<GLRecord, Integer> createColumnConfigInteger(final GLGridColumnDef gridColumnDef,
                                                                  final IGLColumn column) {
  final ColumnConfig<GLRecord, Integer> result;
  final ValueProvider<GLRecord, Integer> valueProvider = new GLIntegerValueProvider(column);
  result = new ColumnConfig<GLRecord, Integer>(valueProvider, gridColumnDef.getWidth(), //
                                               column.getTitle());
  result.setHorizontalAlignment(gridColumnDef.getHorizontalAlignment());
  result.setCell(new NumberCell<Integer>());
  return result;
}
//--------------------------------------------------------------------------------------------------
private ColumnConfig<GLRecord, String> createColumnConfigString(final GLGridColumnDef gridColumnDef,
                                                                final IGLColumn column) {
  final ColumnConfig<GLRecord, String> result;
  final ValueProvider<GLRecord, String> valueProvider = new GLStringValueProvider(column);
  result = new ColumnConfig<GLRecord, String>(valueProvider, gridColumnDef.getWidth(), //
                                              column.getTitle());
  result.setHorizontalAlignment(gridColumnDef.getHorizontalAlignment());
  result.setCell(new TextCell());
  return result;
}
//--------------------------------------------------------------------------------------------------
private ColumnModel<GLRecord> createColumnModel() {
  ColumnModel<GLRecord> result;
  final ArrayList<ColumnConfig<GLRecord, ?>> columnConfigList;
  columnConfigList = new ArrayList<ColumnConfig<GLRecord, ?>>();
  if (_selectionModel instanceof CheckBoxSelectionModel) {
    columnConfigList.add(((CheckBoxSelectionModel<GLRecord>)_selectionModel).getColumn());
  }
  for (final GLGridColumnDef gridColumnDef : _gridColumnDefList) {
    ColumnConfig<GLRecord, ?> columnConfig = null;
    final IGLColumn column = gridColumnDef.getColumn();
    switch (column.getDataType()) {
      case Boolean:
        columnConfig = createColumnConfigBoolean(gridColumnDef, column);
        break;
      case Currency:
        columnConfig = createColumnConfigBigDecimal(gridColumnDef, column);
        break;
      case Date:
        columnConfig = createColumnConfigDateTime(gridColumnDef, column, "dd MMM yyyy");
        break;
      case DateTime:
        columnConfig = createColumnConfigDateTime(gridColumnDef, column, "dd MMM yyyy hh:mm a");
        break;
      case Decimal:
        columnConfig = createColumnConfigBigDecimal(gridColumnDef, column);
        break;
      case Int:
        if (column.getParentTable() == null) {
          columnConfig = createColumnConfigInteger(gridColumnDef, column);
        }
        else {
          columnConfig = createColumnConfigForeignKey(gridColumnDef, column);
        }
        break;
      case String:
        columnConfig = createColumnConfigString(gridColumnDef, column);
        break;
    }
    if (columnConfig != null) {
      gridColumnDef.setColumnConfig(columnConfig, columnConfigList.size());
      columnConfigList.add(columnConfig);
    }
  }
  result = new ColumnModel<GLRecord>(columnConfigList);
  result.addColumnWidthChangeHandler(new ColumnWidthChangeHandler() {
    @Override
    public void onColumnWidthChange(final ColumnWidthChangeEvent event) {
      final ColumnConfig<GLRecord, ?> columnConfig = columnConfigList.get(event.getIndex());
      if (_checkBoxSet.contains(columnConfig)) {
        centerCheckBox(columnConfig);
        _grid.getView().refresh(true);
      }
    }
  });
  for (final ColumnConfig<GLRecord, ?> columnConfig : _checkBoxSet) {
    centerCheckBox(columnConfig);
  }
  return result;
}
//--------------------------------------------------------------------------------------------------
private void createContentPanel(final String headingText) {
  _contentPanel = new ContentPanel();
  if (GLUtil.isBlank(headingText)) {
    _contentPanel.setHeaderVisible(false);
  }
  else {
    _contentPanel.setHeaderVisible(true);
    _contentPanel.setHeadingText(headingText);
  }
  _contentPanel.setButtonAlign(BoxLayoutPack.START);
  _contentPanel.addButton(new TextButton("Reset", new SelectHandler() {
    @Override
    public void onSelect(final SelectEvent event) {
      _listStore.rejectChanges();
    }
  }));
  _contentPanel.addButton(new TextButton("Save", new SelectHandler() {
    @Override
    public void onSelect(final SelectEvent event) {
      _listStore.commitChanges();
    }
  }));
  _contentPanel.addButton(createContentPanelDeleteButton());
  createContentPanelDeleteButton();
}
//--------------------------------------------------------------------------------------------------
private TextButton createContentPanelDeleteButton() {
  return new TextButton("Delete Selected", new SelectHandler() {
    @Override
    public void onSelect(final SelectEvent selectEvent) {
      final List<GLRecord> selectedRecordList = _selectionModel.getSelectedItems();
      if (selectedRecordList.size() == 0) {
        final AlertMessageBox messageBox;
        messageBox = new AlertMessageBox("Delete Rows", "You haven't selected any rows to delete");
        messageBox.show();
        return;
      }
      final String rowMessage;
      if (selectedRecordList.size() == 1) {
        rowMessage = "this row";
      }
      else {
        rowMessage = "these " + selectedRecordList.size() + " rows";
      }
      final ConfirmMessageBox messageBox;
      messageBox = new ConfirmMessageBox("Delete Rows", //
                                         "Are you sure you want to delete " + rowMessage + "?");
      messageBox.addDialogHideHandler(new DialogHideHandler() {
        @Override
        public void onDialogHide(final DialogHideEvent hideEvent) {
          if (hideEvent.getHideButton() == PredefinedButton.YES) {
            final ArrayList<GLRecord> recordList;
            recordList = new ArrayList<GLRecord>(selectedRecordList.size());
            for (final GLRecord record : selectedRecordList) {
              recordList.add(record);
            }
            _listStore.remove(recordList);
          }
        }
      });
      messageBox.show();
    }
  });
}
//--------------------------------------------------------------------------------------------------
@SuppressWarnings("unchecked")
private void createEditors() {
  final GridEditing<GLRecord> gridEditing = new GridInlineEditing<GLRecord>(_grid);
  for (final GLGridColumnDef gridColumnDef : _gridColumnDefList) {
    final ColumnConfig<GLRecord, ?> columnConfig = gridColumnDef.getColumnConfig();
    final IGLColumn column = gridColumnDef.getColumn();
    switch (column.getDataType()) {
      case Boolean:
        // no editor is needed - the checkbox can be changed in place
        break;
      case Currency:
        gridEditing.addEditor((ColumnConfig<GLRecord, BigDecimal>)columnConfig,
                              new BigDecimalField());
        break;
      case Date: {
        final DateTimeFormat dateTimeFormat = DateTimeFormat.getFormat("MM/dd/yyyy");
        final DateTimePropertyEditor propertyEditor = new DateTimePropertyEditor(dateTimeFormat);
        final DateField dateField = new DateField(propertyEditor);
        dateField.setClearValueOnParseError(false);
        gridEditing.addEditor((ColumnConfig<GLRecord, Date>)columnConfig, dateField);
        final IsField<Date> editor = gridEditing.getEditor(columnConfig);
        if (editor == null) {
          GLUtil.initialize();
        }
        break;
      }
      case DateTime: {
        /*
         * In 3, I'd probably start by making an Editor instance with two sub-editors, one DateField
         * and one TimeField, each using @Path("") to have them bind to the same value.
         * 
         * Or make the new class implement IsField, and use setValue() and getValue() to modify/read
         * both sub-editors.
         * 
         * IsField is what is being used in 3 to replace most MultiField cases - it allows a widget
         * to supply methods that are helpful for most fields, and as it extends LeafValueEditor, it
         * can be used in GWT Editor framework, and subfields will be ignored, leaving the dev to
         * write their own logic for binding the values.
         */
        final DateTimeFormat dateTimeFormat = DateTimeFormat.getFormat(PredefinedFormat.DATE_LONG);
        final DateTimePropertyEditor propertyEditor = new DateTimePropertyEditor(dateTimeFormat);
        final DateField dateField = new DateField(propertyEditor);
        dateField.setClearValueOnParseError(false);
        gridEditing.addEditor((ColumnConfig<GLRecord, Date>)columnConfig, dateField);
        break;
      }
      case Decimal:
        gridEditing.addEditor((ColumnConfig<GLRecord, BigDecimal>)columnConfig,
                              new BigDecimalField());
        break;
      case Int:
        if (column.getParentTable() == null) {
          gridEditing.addEditor((ColumnConfig<GLRecord, Integer>)columnConfig, new IntegerField());
        }
        else {
          createEditorsForeignKeyCombobox(gridEditing, gridColumnDef);
        }
        break;
      case String:
        gridEditing.addEditor((ColumnConfig<GLRecord, String>)columnConfig, new TextField());
        break;
    }
  }
}
//--------------------------------------------------------------------------------------------------
@SuppressWarnings("unchecked")
private void createEditorsForeignKeyCombobox(final GridEditing<GLRecord> gridEditing,
                                             final GLGridColumnDef gridColumnDef) {
  final IGLColumn column = gridColumnDef.getColumn();
  final IGLLookupListStoreKey lookupListStoreKey = gridColumnDef.getLookupListStoreKey();
  final GLListStore lookupListStore = getLookupListStore(lookupListStoreKey);
  if (lookupListStore == null) {
    GLUtil.info(10, "Lookup list store not found for column:" + column + " key" +
                    lookupListStoreKey);
    return;
  }
  final LabelProvider<GLRecord> labelProvider = new LabelProvider<GLRecord>() {
    @Override
    public String getLabel(final GLRecord record) {
      try {
        return record.asString(column.getParentDisplayColumn());
      }
      catch (final GLInvalidFieldOrColumnException e) {
        return "???";
      }
    }
  };
  final ComboBox<GLRecord> comboBox = new ComboBox<GLRecord>(lookupListStore, labelProvider);
  final Converter<String, GLRecord> converter = new Converter<String, GLRecord>() {
    @Override
    public GLRecord convertModelValue(final String displayValue) {
      return getRecordForLookupValue(lookupListStoreKey, displayValue);
    }
    @Override
    public String convertFieldValue(final GLRecord record) {
      return "Cat";
    }
  };
  gridEditing.addEditor((ColumnConfig<GLRecord, String>)gridColumnDef.getColumnConfig(), converter,
                        comboBox);
}
//--------------------------------------------------------------------------------------------------
private void createGrid() {
  createCheckBoxSelectionModel();
  final ColumnModel<GLRecord> columnModel = createColumnModel();
  _grid = new Grid<GLRecord>(_listStore, columnModel);
  _grid.addRowClickHandler(new RowClickEvent.RowClickHandler() {
    @Override
    public void onRowClick(final RowClickEvent event) {
      final Collection<Store<GLRecord>.Record> records = _listStore.getModifiedRecords();
      if (records.size() > 0) {
        _grid.setBorders(false);
      }
    }
  });
  _grid.setBorders(true);
  _grid.setColumnReordering(true);
  _grid.setLoadMask(true);
  _grid.setSelectionModel(_selectionModel);
  _grid.setView(createGridView());
  addHeaderContextMenuHandler();
  createEditors();
}
//--------------------------------------------------------------------------------------------------
private void createGridColumnDefMap() {
  _gridColumnDefMap = new TreeMap<String, GLGridColumnDef>();
  for (final GLGridColumnDef gridColumnDef : _gridColumnDefList) {
    _gridColumnDefMap.put(gridColumnDef.getColumn().toString(), gridColumnDef);
  }
}
//--------------------------------------------------------------------------------------------------
private GridView<GLRecord> createGridView() {
  final GridView<GLRecord> result = new GridView<GLRecord>();
  result.setColumnLines(true);
  result.setEmptyText(_noRowsMessage);
  result.setForceFit(false);
  result.setStripeRows(true);
  return result;
}
//--------------------------------------------------------------------------------------------------
public GLListStore getListStore() {
  return _listStore;
}
//--------------------------------------------------------------------------------------------------
public GLListStore getLookupListStore(final IGLLookupListStoreKey lookupListStoreKey) {
  return null;
}
//--------------------------------------------------------------------------------------------------
public GLRecord getRecordForLookupValue(final IGLLookupListStoreKey lookupListStoreKey,
                                        final String value) {
  return null;
}
//--------------------------------------------------------------------------------------------------
protected abstract void loadGridColumnDefList();
//--------------------------------------------------------------------------------------------------
private void resizeColumnToFit(final int columnIndex) {
  final ColumnConfig<GLRecord, ?> columnConfig = _grid.getColumnModel().getColumn(columnIndex);
  final TextMetrics textMetrics = TextMetrics.get();
  textMetrics.bind(_grid.getView().getHeader().getAppearance().styles().head());
  int maxWidth = textMetrics.getWidth(columnConfig.getHeader().asString()) + 15; // extra is for the dropdown arrow
  if (_listStore.size() > 0) {
    textMetrics.bind(_grid.getView().getCell(0, 1));
    for (final GLRecord record : _listStore.getAll()) {
      final Object value = columnConfig.getValueProvider().getValue(record);
      if (value != null) {
        String valueAsString;
        if (columnConfig.getCell() instanceof DateCell) {
          final DateCell dateCell = (DateCell)columnConfig.getCell();
          final SafeHtmlBuilder sb = new SafeHtmlBuilder();
          dateCell.render(null, (Date)value, sb);
          valueAsString = sb.toSafeHtml().asString();
        }
        else {
          valueAsString = value.toString();
        }
        final int width = textMetrics.getWidth(valueAsString) + 12;
        maxWidth = width > maxWidth ? width : maxWidth;
      }
    }
    for (final Store<GLRecord>.Record record : _listStore.getModifiedRecords()) {
      final int width = textMetrics.getWidth(record.getValue(columnConfig.getValueProvider()) //
                                                   .toString()) + 12;
      maxWidth = width > maxWidth ? width : maxWidth;
    }
  }
  columnConfig.setWidth(maxWidth);
  if (_checkBoxSet.contains(columnConfig)) {
    centerCheckBox(columnConfig);
  }
}
//--------------------------------------------------------------------------------------------------
private void resizeNextColumn(final ProgressMessageBox messageBox, final int columnIndex,
                              final int lastColumnIndex) {
  Scheduler.get().scheduleDeferred(new ScheduledCommand() {
    @Override
    public void execute() {
      resizeColumnToFit(columnIndex);
      if (columnIndex == lastColumnIndex) {
        messageBox.hide();
        _grid.getView().refresh(true);
        return;
      }
      messageBox.updateProgress((double)columnIndex / (lastColumnIndex + 1), "{0}% Complete");
      resizeNextColumn(messageBox, columnIndex + 1, lastColumnIndex);
    }
  });
}
//--------------------------------------------------------------------------------------------------
}